import * as THREE from 'three';
// Orbit controls（轨道控制器）可以使得相机围绕目标进行轨道运动
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
/**
 * 为了真正能够让你的场景借助 three.js 来进行显示，
 * 需要以下几个对象：场景（scene）、相机（camera）和渲染器（renderer），
 * 就能透过摄像机渲染出场景。
 * */
const scene = new THREE.Scene();
/**
 * PerspectiveCamera（透视摄像机）
 * 第一个参数是视野角度（FOV）
 *    视野角度就是无论在什么时候，你所能在显示器上看到的场景的范围，它的单位是角度(与弧度区分开)。
 * 第二个参数是长宽比（aspect ratio）
 *    用一个物体的宽除以它的高的值。比如说，当你在一个宽屏电视上播放老电影时，可以看到图像仿佛是被压扁的。
 * 接下来的两个参数是近截面（near）和远截面（far）
 *    当物体某些部分比摄像机的远截面远或者比近截面近的时候，该这些部分将不会被渲染到场景中。
 *    或许现在你不用担心这个值的影响，但未来为了获得更好的渲染性能，你将可以在你的应用程序里去设置它。
 */
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

camera.position.set(2, 100, 20)
camera.lookAt(0,0,0)
/**
 * 接下来是渲染器。
 *    在这里用到的 WebGLRenderer 渲染器之外，Three.js 同时提供了其他几种渲染器，当用户所使用的浏览器过于老旧，或者由于其他原因不支持 WebGL 时，可以使用这几种渲染器进行降级。
 */
const renderer = new THREE.WebGLRenderer({
  canvas: document.querySelector('#canvas'), //指定渲染的容器，不添加则会自动生成
  antialias: true, //抗锯齿 像素点
});



/**
 *    还需要在我们的应用程序里设置一个渲染器的尺寸。比如说，我们可以使用所需要的渲染区域的宽高，来让渲染器渲染出的场景填充满我们的应用程序。
 *    因此，我们可以将渲染器宽高设置为浏览器窗口宽高。
 *    对于性能比较敏感的应用程序来说，可以使用 setSize 传入一个较小的值，例如 window.innerWidth/2 和 window.innerHeight/2，这将使得应用程序在渲染时，以一半的长宽尺寸渲染场景。
 *    如果希望保持应用程序的尺寸，但是以较低的分辨率来渲染，可在调用 setSize 时，将 updateStyle（第三个参数）设为 false。
 *    例如，假设你的 <canvas> 标签现在已经具有了 100% 的宽和高，调用 setSize(window.innerWidth/2, window.innerHeight/2, false) 将使得你的应用程序以四分之一的大小来进行渲染。
 *    最后一步很重要，我们将 renderer（渲染器）的dom元素（renderer.domElement）添加到我们的 HTML 文档中。这就是渲染器用来显示场景给我们看的 <canvas> 元素。
 */
// renderer.setSize( window.innerWidth, window.innerHeight ); //设置渲染器的大小
/**
 *    最后一步很重要，我们将 renderer（渲染器）的dom元素（renderer.domElement）添加到我们的 HTML 文档中。这就是渲染器用来显示场景给我们看的 <canvas> 元素。
 */
// document.body.appendChild( renderer.domElement ); //则需要添加至页面

// 创建坐标网格辅助线
const size = 100;
const divisions = 10;

const gridHelper = new THREE.GridHelper( size, divisions, 0xff0000 );

/**
 * 创建一个立方体，
 * 1、需要一个 BoxGeometry（立方体）对象. 这个对象包含了一个立方体中所有的顶点（vertices）和面（faces）
 * 2、给它一个材质，来让它有颜色。
 *    Three.js 自带了几种材质，在这里我们使用的是 MeshBasicMaterial。
 *    所有的材质都存有应用于他们的属性的对象。在这里为了简单起见，我们只设置一个color属性，值为 0x00ff00，也就是绿色。
 *    这里所做的事情，和在 CSS 或者 Photoshop 中使用十六进制（hex colors）颜色格式来设置颜色的方式一致。
 * 3、需要一个 Mesh（网格）。 
 *    网格包含一个几何体以及作用在此几何体上的材质，我们可以直接将网格对象放入到我们的场景中，并让它在场景中自由移动。
 * 4、默认情况下，当调用 scene.add() 的时候，物体将会被添加到 (0,0,0) 坐标。
 *    但将使得摄像机和立方体彼此在一起。为了防止这种情况的发生，我们只需要将摄像机稍微向外移动一些即可。
 */

// 创建结构   几何体 圆锥
// radius — 圆锥底部的半径，默认值为1。
// height — 圆锥的高度，默认值为1。
// radialSegments — 圆锥侧面周围的分段数，默认为32。
const geometry = new THREE.ConeGeometry(15,50,32)
// 创建材质  外观
const material = new THREE.MeshBasicMaterial({ 
  color: 0xB696FF, //颜色
  transparent: true, //开启透明
  opacity: .5,//设置透明度
}) 
// 结构和材质组合 生成一个物体
const mesh  = new THREE.Mesh(geometry, material); //创建方块实例对象
mesh.position.y = 20


// 模拟3个坐标轴的对象.
// 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
const axesHelper = new THREE.AxesHelper(150);
// 设置x,y,z轴的颜色
axesHelper.setColors(new THREE.Color(0xff0000), new THREE.Color(0x00ff00), new THREE.Color('pink'))


scene.add( gridHelper, mesh, axesHelper );

// 控制器的使用
// 控制器实例化  参数：相机  绑定事件的元素
const controls = new OrbitControls( camera, renderer.domElement );

//controls.update() must be called after any manual changes to the camera's transform
controls.enableDamping = true


controls.addEventListener('change', () => {
  renderer.render( scene, camera )
  console.log(camera.position);
  
})

renderer.render( scene, camera )

/**
 * 进行真正的渲染
 * 需要使用一个被叫做“渲染循环”（render loop）或者“动画循环”（animate loop）的东西。
 */
function animate() {
	requestAnimationFrame( animate );
  controls.update();
	// renderer.render( scene, camera );  //render  执行一次渲染一次
}
animate();
